import cv2
import numpy as np
import matplotlib.pyplot as plt
import os
import time
from paddleocr import PaddleOCR

# 修复numpy兼容性问题
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)

# 为了兼容旧版本的PaddleOCR，添加np.int的兼容性处理
if not hasattr(np, 'int'):
    np.int = int
if not hasattr(np, 'float'):
    np.float = float
if not hasattr(np, 'bool'):
    np.bool = bool

# 设置Matplotlib支持中文显示
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

class LicensePlateProcessor:
    def __init__(self):
        self.plate_coords = None
        self.binary_image = None
        self.cropped_color_plate = None  # 保存裁剪后的彩色车牌
        self.segmentation_img = None     # 保存分割图像
        self.characters = []
        # 中文字符集（省份简称）
        self.chinese_chars = {'京', '沪', '津', '渝', '冀', '晋', '蒙', '辽', '吉', '黑', 
                             '苏', '浙', '皖', '闽', '赣', '鲁', '豫', '鄂', '湘', '粤', 
                             '桂', '琼', '川', '贵', '云', '藏', '陕', '甘', '青', '宁', '新'}
        
        # 初始化PaddleOCR（使用官方demo的初始化方式）
        try:
            # 参考官方demo的初始化参数
            self.ocr = PaddleOCR(use_angle_cls=True, lang='ch', use_gpu=False, show_log=False)
            print("PaddleOCR初始化成功")
        except Exception as e:
            print(f"PaddleOCR初始化失败: {str(e)}")
            print("请确保已安装paddlepaddle和paddleocr")
            print("推荐安装命令: pip install paddlepaddle paddleocr==2.5.0.3")
            self.ocr = None

    def sliding_window_detection(self, image_path, window_width, window_height, step_size):
        """滑窗检测定位车牌"""
        img = cv2.imread(image_path)
        if img is None:
            print("无法读取图片，请检查文件路径")
            return None
            
        img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        
        # 滑窗参数
        window_width = window_width
        window_height = window_height
        step_size = step_size

        # 搜索区域
        search_y_start = img.shape[0] // 3
        search_y_end = img.shape[0] * 3 // 4
        search_x_start = img.shape[1] // 6
        search_x_end = img.shape[1] * 5 // 6
        
        # 创建可视化窗口
        plt.figure(figsize=(12, 8))
        plt.ion()
        
        best_plate = None
        best_score = 0
        frame_count = 0
        
        print("开始滑窗搜索车牌...")
        
        # 滑窗搜索过程
        for y in range(search_y_start, search_y_end - window_height, step_size):
            for x in range(search_x_start, search_x_end - window_width, step_size):
                frame_count += 1
                
                # 提取窗口区域
                window = img_gray[y:y+window_height, x:x+window_width]
                
                if window.size == 0:
                    continue
                
                # 计算车牌可能性分数
                score, is_plate = self.calculate_plate_score_improved(window, img[y:y+window_height, x:x+window_width])
                
                # 更新最佳区域
                if is_plate and score > best_score:
                    best_score = score
                    best_plate = (x, y, window_width, window_height)
                
                # 实时显示滑窗过程
                if frame_count % 12 == 0:
                    display_img = img_rgb.copy()
                    
                    # 绘制当前窗口
                    cv2.rectangle(display_img, (x, y), (x+window_width, y+window_height), (255, 205, 3), 3)
                    
                    # 绘制当前最佳窗口
                    if best_plate:
                        bx, by, bw, bh = best_plate
                        cv2.rectangle(display_img, (bx, by), (bx+bw, by+bh), (255, 205, 3), 3)
                    
                    plt.clf()
                    plt.imshow(display_img)
                    plt.title(f'滑窗搜索中... 分数: {score:.1f}')
                    plt.axis('off')
                    plt.pause(0.001)
        
        # 显示找到车牌的过程
        if best_plate and best_score > 40:
            print(f"找到车牌候选区域，分数: {best_score:.1f}")
            
            # 精确定位
            final_plate = self.refine_plate_position(img_gray, best_plate)
            self.plate_coords = final_plate
            
            # 显示最终结果
            plt.ioff()
            plt.close()
            
            final_img = img_rgb.copy()
            x, y, w, h = final_plate
            
            # 用红色框标出最终定位
            cv2.rectangle(final_img, (x, y), (x+w, y+h), (255, 0, 0), 3)
            cv2.putText(final_img, '车牌', (x, y-15), 
                       cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2)
            
            plt.figure(figsize=(12, 8))
            plt.imshow(final_img)
            plt.title('车牌定位完成')
            plt.axis('off')
            plt.show()
            
            return final_img
        else:
            plt.ioff()
            plt.close()
            #print("滑窗检测未找到合适车牌，使用颜色特征检测...")
            return self.color_based_detection(image_path)
    
    def calculate_plate_score_improved(self, gray_window, color_window):
        """改进的车牌评分算法"""
        if gray_window.size == 0:
            return 0, False
        
        # 字符纹理特征
        sobelx = cv2.Sobel(gray_window, cv2.CV_64F, 1, 0, ksize=3)
        sobely = cv2.Sobel(gray_window, cv2.CV_64F, 0, 1, ksize=3)
        gradient_magnitude = np.sqrt(sobelx**2 + sobely**2)
        texture_score = np.mean(gradient_magnitude)
        
        # 边缘密度
        edges = cv2.Canny(gray_window, 50, 150)
        edge_density = np.sum(edges > 0) / gray_window.size
        
        # 对比度
        contrast_score = np.std(gray_window)
        
        # 垂直投影特征
        vertical_proj = np.sum(gray_window < 100, axis=0)
        
        # 计算字符间隔特征
        char_peaks = 0
        char_valleys = 0
        in_char = False
        
        for i in range(1, len(vertical_proj)-1):
            if (vertical_proj[i] > vertical_proj[i-1] and 
                vertical_proj[i] > vertical_proj[i+1] and 
                vertical_proj[i] > gray_window.shape[0] * 0.2):
                if not in_char:
                    char_peaks += 1
                    in_char = True
            elif (vertical_proj[i] < vertical_proj[i-1] and 
                  vertical_proj[i] < vertical_proj[i+1] and 
                  vertical_proj[i] < gray_window.shape[0] * 0.1):
                if in_char:
                    char_valleys += 1
                    in_char = False
        
        # 颜色特征
        hsv_window = cv2.cvtColor(color_window, cv2.COLOR_BGR2HSV)
        
        # 蓝色车牌范围
        lower_blue = np.array([100, 50, 50])
        upper_blue = np.array([130, 255, 255])
        blue_mask = cv2.inRange(hsv_window, lower_blue, upper_blue)
        blue_ratio = np.sum(blue_mask > 0) / blue_mask.size
        
        # 黄色车牌范围
        lower_yellow = np.array([15, 50, 50])
        upper_yellow = np.array([35, 255, 255])
        yellow_mask = cv2.inRange(hsv_window, lower_yellow, upper_yellow)
        yellow_ratio = np.sum(yellow_mask > 0) / yellow_mask.size
        
        # 白色/银色区域
        lower_white = np.array([0, 0, 200])
        upper_white = np.array([180, 30, 255])
        white_mask = cv2.inRange(hsv_window, lower_white, upper_white)
        white_ratio = np.sum(white_mask > 0) / white_mask.size
        
        # 亮度分布
        brightness_mean = np.mean(gray_window)
        brightness_std = np.std(gray_window)
        
        # 判断是否为车灯
        is_headlight = (
            white_ratio > 0.3 or
            brightness_mean > 180 or
            brightness_std < 20 or
            char_peaks < 4 or
            edge_density < 0.05
        )
        
        # 判断是否为车牌
        is_license_plate = (
            char_peaks >= 5 and
            char_peaks <= 9 and
            edge_density > 0.08 and
            contrast_score > 25 and
            (blue_ratio > 0.1 or yellow_ratio > 0.1)
        )
        
        # 如果是车灯，返回低分
        if is_headlight:
            return min(20, texture_score * 0.1), False
        
        # 计算综合分数
        if is_license_plate:
            total_score = (
                texture_score * 0.15 +
                edge_density * 200 * 0.25 +
                contrast_score * 0.15 +
                char_peaks * 8 * 0.25 +
                (blue_ratio + yellow_ratio) * 100 * 0.2
            )
            return total_score, True
        else:
            total_score = (
                texture_score * 0.1 +
                edge_density * 150 * 0.2 +
                contrast_score * 0.1 +
                char_peaks * 5 * 0.2
            )
            return total_score, False
    
    def refine_plate_position(self, gray_img, rough_plate):
        """精确定位车牌"""
        x, y, w, h = rough_plate
        
        # 在粗略位置周围小范围搜索
        search_margin = 20
        best_x, best_y, best_w, best_h = x, y, w, h
        best_score = 0
        
        for width in range(w-10, w+11, 3):
            for height in range(h-5, h+6, 2):
                if width < 140 or height < 35:
                    continue
                    
                for offset_x in range(-search_margin, search_margin+1, 5):
                    for offset_y in range(-search_margin, search_margin+1, 3):
                        new_x = max(0, x + offset_x)
                        new_y = max(0, y + offset_y)
                        
                        if (new_x + width > gray_img.shape[1] or 
                            new_y + height > gray_img.shape[0]):
                            continue
                            
                        window = gray_img[new_y:new_y+height, new_x:new_x+width]
                        if window.size == 0:
                            continue
                            
                        score, is_plate = self.calculate_plate_score_improved(window, 
                                                                             np.stack([window]*3, axis=-1))
                        if is_plate and score > best_score:
                            best_score = score
                            best_x, best_y, best_w, best_h = new_x, new_y, width, height
        
        return (best_x, best_y, best_w, best_h)
    
    def color_based_detection(self, image_path):
        """基于颜色的车牌检测"""
        img = cv2.imread(image_path)
        img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
        
        # 蓝色车牌
        lower_blue = np.array([100, 80, 80])
        upper_blue = np.array([130, 255, 255])
        blue_mask = cv2.inRange(hsv, lower_blue, upper_blue)
        
        # 黄色车牌
        lower_yellow = np.array([15, 80, 80])
        upper_yellow = np.array([35, 255, 255])
        yellow_mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
        
        # 合并颜色掩码
        color_mask = cv2.bitwise_or(blue_mask, yellow_mask)
        
        # 形态学操作
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
        color_mask = cv2.morphologyEx(color_mask, cv2.MORPH_CLOSE, kernel)
        color_mask = cv2.morphologyEx(color_mask, cv2.MORPH_OPEN, kernel)
        
        # 查找轮廓
        contours, _ = cv2.findContours(color_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        
        best_contour = None
        best_score = 0
        
        for contour in contours:
            x, y, w, h = cv2.boundingRect(contour)
            aspect_ratio = w / h
            
            # 车牌形状特征
            if 2.2 < aspect_ratio < 4.5 and w > 120 and h > 30:
                # 计算轮廓内的颜色一致性
                roi = img[y:y+h, x:x+w]
                if roi.size == 0:
                    continue
                    
                hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
                blue_ratio = np.sum(cv2.inRange(hsv_roi, lower_blue, upper_blue) > 0) / (w*h)
                yellow_ratio = np.sum(cv2.inRange(hsv_roi, lower_yellow, upper_yellow) > 0) / (w*h)
                
                color_score = max(blue_ratio, yellow_ratio)
                shape_score = 1.0 - min(abs(aspect_ratio - 3.0) / 3.0, 1.0)
                
                total_score = color_score * 0.7 + shape_score * 0.3
                
                if total_score > best_score:
                    best_score = total_score
                    best_contour = (x, y, w, h)
        
        if best_contour and best_score > 0.3:
            x, y, w, h = best_contour
            self.plate_coords = (x, y, w, h)
            
            result_img = img_rgb.copy()
            cv2.rectangle(result_img, (x, y), (x+w, y+h), (255, 0, 0), 3)
            cv2.putText(result_img, 'Find Detection', (x, y-10), 
                       cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
            
            plt.figure(figsize=(12, 8))
            plt.imshow(result_img)
            plt.title('颜色特征检测 - 车牌定位结果')
            plt.axis('off')
            plt.show()
            
            return result_img
        
        print("所有方法都未能找到车牌")
        return None
    
    def crop_and_binarize(self, image_path):
        """裁剪车牌并进行二值化处理"""
        if self.plate_coords is None:
            print("请先进行车牌定位")
            return None
            
        img = cv2.imread(image_path)
        x, y, w, h = self.plate_coords
        
        # 裁剪车牌区域（适当扩展）
        expand = 8
        x_start = max(0, x - expand)
        y_start = max(0, y - expand)
        x_end = min(img.shape[1], x + w + expand)
        y_end = min(img.shape[0], y + h + expand)
        
        plate_region = img[y_start:y_end, x_start:x_end]
        cv2.imwrite('Cropped.png', plate_region)  # 保存裁剪的车牌图片
        if plate_region.size == 0:
            print("裁剪区域无效")
            return None
        
        # 转换为灰度图
        gray_plate = cv2.cvtColor(plate_region, cv2.COLOR_BGR2GRAY)
        
        # 改进的二值化处理
        blurred = cv2.GaussianBlur(gray_plate, (3, 3), 0)
        # 对不同亮度的车牌使用不同的阈值方法
        if np.mean(blurred) > 127:
            _, binary_plate = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
        else:
            _, binary_plate = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
        
        # 形态学操作去除噪声
        kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2, 2))
        binary_plate = cv2.morphologyEx(binary_plate, cv2.MORPH_CLOSE, kernel)
        binary_plate = cv2.morphologyEx(binary_plate, cv2.MORPH_OPEN, kernel)
        
        # 保存二值化图片
        cv2.imwrite('Binary.png', binary_plate)
        self.binary_image = binary_plate
        self.cropped_color_plate = plate_region  # 保存彩色原图
        # 显示结果
        plt.figure(figsize=(12, 4))
        plt.subplot(1, 2, 1)
        plt.imshow(cv2.cvtColor(plate_region, cv2.COLOR_BGR2RGB))
        plt.title('裁剪的车牌区域')
        plt.axis('off')
        
        plt.subplot(1, 2, 2)
        plt.imshow(binary_plate, cmap='gray')
        plt.title('二值化结果')
        plt.axis('off')
        
        plt.tight_layout()
        plt.show()
        
        return binary_plate
    
    def correct_skew(self, image):
        """校正车牌倾斜"""
        # 查找轮廓
        contours, _ = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        if not contours:
            return image
            
        # 找到最长的轮廓
        longest_contour = max(contours, key=cv2.contourArea)
        
        # 拟合最小外接矩形
        rect = cv2.minAreaRect(longest_contour)
        angle = rect[2]
        
        # 调整角度（确保旋转方向正确）
        if angle < -45:
            angle += 90
        elif angle > 45:
            angle -= 90
            
        # 如果倾斜角度很小，不需要校正
        if abs(angle) < 1:
            return image
            
        # 执行旋转校正
        (h, w) = image.shape[:2]
        center = (w // 2, h // 2)
        M = cv2.getRotationMatrix2D(center, angle, 1.0)
        corrected = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
        
        return corrected
    
    def character_segmentation(self, image=None):
        """优化的字符分割算法，确保7个字符和8条分割线"""
        # 如果传入了二值化图像，直接使用
        if image is not None:
            self.binary_image = image
        # 如果没有传入图像且self.binary_image为空，尝试加载Binary.png
        elif self.binary_image is None:
            try:
                self.binary_image = cv2.imread('Binary.png', cv2.IMREAD_GRAYSCALE)
                if self.binary_image is None:
                    print("无法加载Binary.png文件，请确保文件存在")
                    return None
                print("已加载Binary.png文件")
            except Exception as e:
                print(f"加载Binary.png时出错: {e}")
                return None
        
        # 检查binary_image是否有效
        if self.binary_image is None or self.binary_image.size == 0:
            print("错误：二值化图像为空或无效")
            return None

        # 复制二值化图像用于处理
        binary_img = self.binary_image.copy()
        
        
        # 校正倾斜
        corrected_img = self.correct_skew(binary_img)
        height, width = corrected_img.shape
        
        # 计算垂直投影（统计黑色像素，即字符部分）
        vertical_projection = np.sum(corrected_img == 0, axis=0)
        
        # 平滑投影曲线，减少噪声影响
        kernel_size = 7
        vertical_projection = np.convolve(vertical_projection, np.ones(kernel_size)/kernel_size, mode='same')
        
        '''# 显示垂直投影图，便于调试
        plt.figure(figsize=(12, 4))
        plt.plot(vertical_projection)
        plt.title('垂直投影分布 - 用于字符分割')
        plt.grid(True)
        plt.show()'''
        
        # 找到字符边界 - 改进算法
        char_regions = []
        in_char = False
        start = 0
        min_char_width = width * 0.05  # 最小字符宽度
        threshold = np.max(vertical_projection) * 0.3  # 投影阈值
        
        for i in range(width):
            # 检测字符开始
            if vertical_projection[i] > threshold and not in_char:
                start = i
                in_char = True
            # 检测字符结束
            elif vertical_projection[i] <= threshold and in_char:
                end = i
                in_char = False
                # 过滤过小的区域
                if end - start > min_char_width:
                    char_regions.append((start, end))
        
        # 处理最后一个字符
        if in_char and width - start > min_char_width:
            char_regions.append((start, width-1))
        
        # 关键改进：强制确保7个字符和8条分割线
        # 中国车牌标准是7个字符，所以需要8条分割线
        target_chars = 7
        
        # 情况1：字符数量少于7个，拆分最宽的区域
        while len(char_regions) < target_chars:
            max_width = -1
            max_idx = 0
            for i, (s, e) in enumerate(char_regions):
                if e - s > max_width:
                    max_width = e - s
                    max_idx = i
            
            # 拆分最宽的字符区域
            s, e = char_regions[max_idx]
            mid = s + (e - s) // 2
            # 插入拆分后的两个区域
            char_regions = (char_regions[:max_idx] + 
                           [(s, mid), (mid, e)] + 
                           char_regions[max_idx+1:])
        
        # 情况2：字符数量多于7个，合并最窄的区域
        while len(char_regions) > target_chars:
            min_width = float('inf')
            min_idx = 0
            for i, (s, e) in enumerate(char_regions):
                if e - s < min_width:
                    min_width = e - s
                    min_idx = i
            
            # 合并最窄的字符区域
            if min_idx == 0:
                s1, e1 = char_regions[0]
                s2, e2 = char_regions[1]
                char_regions = [(s1, e2)] + char_regions[2:]
            else:
                s1, e1 = char_regions[min_idx-1]
                s2, e2 = char_regions[min_idx]
                char_regions = char_regions[:min_idx-1] + [(s1, e2)] + char_regions[min_idx+1:]
        
        # 使用中国车牌字符标准比例进行精确调整
        # 第一个字符（汉字）占17%，其余6个字符各占约13.8%
        total_width = width
        # 8条分割线的理想位置（0到1之间的比例）
        split_positions = [
            0.00,   # 第1条线
            0.17,   # 第2条线（汉字结束）
            0.32,   # 第3条线
            0.47,   # 第4条线
            0.59,   # 第5条线
            0.71,   # 第6条线
            0.83,   # 第7条线
            1.00    # 第8条线
        ]
        
        # 计算实际分割线位置
        actual_splits = [int(pos * total_width) for pos in split_positions]
        
        # 确保分割线在图像范围内
        actual_splits[0] = 0
        actual_splits[-1] = width - 1
        
        # 创建分割可视化图
        segmentation_img = cv2.cvtColor(corrected_img, cv2.COLOR_GRAY2BGR)
        
        # 绘制8条红色分割线
        for split in actual_splits:
            cv2.line(segmentation_img, (split, 0), (split, height), (0, 0, 255), 2)
        
        # 提取每个字符区域
        self.characters = []
        for i in range(len(actual_splits) - 1):
            start = actual_splits[i]
            end = actual_splits[i + 1]
            
            # 裁剪字符
            char_img = corrected_img[:, start:end]
            
            # 预处理字符
            char_img = self.preprocess_character(char_img)
            
            # 保存字符
            char_filename = f'zifu{i+1}.png'
            cv2.imwrite(char_filename, char_img)
            self.characters.append(char_img)
            print(f"保存字符: {char_filename}")
        
        # 保存分割结果
        cv2.imwrite('qiege.png', segmentation_img)
        self.segmentation_img = segmentation_img
        # 显示结果
        plt.figure(figsize=(15, 5))
        plt.subplot(1, 2, 1)
        plt.imshow(corrected_img, cmap='gray')
        plt.title('校正后的二值化车牌')
        plt.axis('off')
        
        plt.subplot(1, 2, 2)
        plt.imshow(cv2.cvtColor(segmentation_img, cv2.COLOR_BGR2RGB))
        plt.title('字符分割结果（8条红色分割线）')
        plt.axis('off')
        plt.tight_layout()
        plt.show()
        
        # 显示单个字符
        if self.characters:
            plt.figure(figsize=(15, 3))
            for i, char_img in enumerate(self.characters):
                plt.subplot(1, len(self.characters), i+1)
                plt.imshow(cv2.cvtColor(char_img, cv2.COLOR_BGR2RGB))
                plt.title(f'字符 {i+1}')
                plt.axis('off')
            plt.tight_layout()
            plt.show()
        
        return segmentation_img
    
    def preprocess_character(self, char_img):
        """预处理单个字符，提高识别率"""
        # 调整大小为统一尺寸
        h, w = char_img.shape
        if h == 0 or w == 0:
            return np.zeros((60, 40, 3), dtype=np.uint8)  # 确保返回3通道图像
            
        # 保持宽高比缩放
        scale = min(60/h, 40/w)
        new_h, new_w = int(h*scale), int(w*scale)
        char_img = cv2.resize(char_img, (new_w, new_h), interpolation=cv2.INTER_AREA)
        
        # 居中放置在固定大小的画布上
        canvas = np.ones((60, 40), dtype=np.uint8) * 255
        y_offset = (60 - new_h) // 2
        x_offset = (40 - new_w) // 2
        canvas[y_offset:y_offset+new_h, x_offset:x_offset+new_w] = char_img
        
        # 去除噪声
        kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (1, 1))
        canvas = cv2.morphologyEx(canvas, cv2.MORPH_OPEN, kernel)
        
        # 转换为BGR格式，因为PaddleOCR需要3通道输入
        return cv2.cvtColor(canvas, cv2.COLOR_GRAY2BGR)
    
    def recognize_plate(self):
        """修改后的第四步：直接使用Binary.png进行整体识别"""
        if self.binary_image is None:
            print("请先进行二值化处理")
            return None
            
        if self.ocr is None:
            print("PaddleOCR未初始化，无法进行识别")
            return None
        
        try:
            # 直接识别二值化后的车牌图片
            res = self.ocr.ocr("Binary.png", cls=True)
            
            # 检查识别结果是否有效
            if not res or len(res) == 0 or len(res[0]) == 0:
                print("未识别到车牌内容")
                return None
            
            # 提取原始文本（根据PaddleOCR返回的结构）
            original_text = res[0][1][0]
            #print(f"原始识别结果: {original_text}")
            
            # 去除·符号
            cleaned_text = original_text.replace("·", "")
            
            # 进一步清理识别结果，只保留有效字符
            valid_chars = set(self.chinese_chars)
            valid_chars.update([chr(ord('A') + i) for i in range(26)])
            valid_chars.update([str(i) for i in range(10)])
            final_text = ''.join([c for c in cleaned_text if c in valid_chars])
            
            print("=" * 50)
            print(f"车牌识别结果: {final_text}")
            print("=" * 50)
            
            # 显示识别结果
            plt.figure(figsize=(18, 6))

            self.cropped_color_plate = cv2.imread('Cropped.png', cv2.COLOR_BGR2RGB)
            # 第一张图：裁剪后的原始彩色车牌
            plt.subplot(1, 3, 1)
            if self.cropped_color_plate is not None and self.cropped_color_plate.size > 0:
                plt.imshow(cv2.cvtColor(self.cropped_color_plate, cv2.COLOR_BGR2RGB))
                plt.title('裁剪的原始车牌')
            else:
                plt.text(0.5, 0.5, '原始车牌图像不可用', ha='center', va='center', transform=plt.gca().transAxes)
                plt.title('裁剪的原始车牌 (不可用)')
            plt.axis('off')

            # 第二张图：二值化图像
            plt.subplot(1, 3, 2)
            if self.binary_image is not None and self.binary_image.size > 0:
                plt.imshow(self.binary_image, cmap='gray')
                plt.title('二值化结果')
            else:
                plt.text(0.5, 0.5, '二值化图像不可用', ha='center', va='center', transform=plt.gca().transAxes)
                plt.title('二值化结果 (不可用)')
            plt.axis('off')

            # 第三张图：分割图像
            plt.subplot(1, 3, 3)
            if self.segmentation_img is not None and self.segmentation_img.size > 0:
                plt.imshow(cv2.cvtColor(self.segmentation_img, cv2.COLOR_BGR2RGB))
                plt.title(f'车牌识别结果: {final_text}')
            else:
                plt.text(0.5, 0.5, f'车牌识别结果: {final_text}\n(分割图像不可用)', ha='center', va='center', transform=plt.gca().transAxes)
                plt.title(f'车牌识别结果: {final_text}')
            plt.axis('off')

            plt.tight_layout()
            plt.show()

            '''plt.figure(figsize=(10, 6))
            plt.imshow(self.binary_image, cmap='gray')
            plt.title(f'车牌识别结果: {final_text}')
            plt.axis('off')
            plt.show()'''
            
            return final_text
            
        except Exception as e:
            print(f"识别过程出错: {str(e)}")
            return None
    
    def clean_recognized_text(self, text, position=-1):
        """清理识别结果，过滤无效字符"""
        # 移除空白字符和特殊符号
        cleaned = ''.join([c for c in text if c.strip()])
        
        # 根据位置过滤（第一个字符应为中文字符，其他为字母数字）
        if position == 0:  # 第一个字符
            # 只保留有效的省份简称
            for c in cleaned:
                if c in self.chinese_chars:
                    return c
            return '?'  # 无法识别的字符用?代替
        elif position > 0:  # 其他字符
            # 只保留字母和数字，转为大写
            for c in cleaned:
                if c.isalnum():
                    return c.upper()
            return '?'  # 无法识别的字符用?代替
        else:  # 整体识别
            # 过滤所有非车牌字符
            valid_chars = set(self.chinese_chars)
            valid_chars.update([chr(ord('A') + i) for i in range(26)])
            valid_chars.update([str(i) for i in range(10)])
            
            return ''.join([c for c in cleaned if c in valid_chars])
    
    def process_complete_pipeline(self, image_path):
        """完整的处理流程"""
        if self.ocr is None:
            return None
            
        print("开始车牌处理流程...")
        print("=" * 50)
        
        # 第一步：滑窗车牌定位
        print("第一步：滑窗车牌定位")
        start_time = time.time()
        result_img = self.sliding_window_detection(image_path)
        end_time = time.time()
        
        if result_img is None:
            print("车牌定位失败，无法继续处理")
            return None
        
        print(f"车牌定位耗时: {end_time - start_time:.2f} 秒")
        
        # 第二步：车牌裁剪和二值化
        print("第二步：车牌裁剪和二值化")
        self.crop_and_binarize(image_path)
        
        # 第三步：字符分割（虽然修改了第四步，但保留分割步骤以便观察）
        print("第三步：字符分割")
        self.character_segmentation()
        
        # 第四步：车牌识别（已修改为直接识别Binary.png）
        print("第四步：车牌识别")
        result = self.recognize_plate()
        
        return result
